package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
)

func main() {
	// simpleReader()
	// demoChainReader()
	// WriterDemo()
	PipeDemo()
}

func WriterDemo() {
	// SimpleWriter()
	MyWriterDemo()
	// PipeDemo()
}

/* 从缓冲区中将数据写入到resource */

func SimpleWriter() {
	var w bytes.Buffer
	data := []string{
		"hello world",
		"this is sean",
		"hahahaha",
	}

	for _, d := range data {
		n, err := w.Write([]byte(d))
		if nil != err {
			fmt.Println("get an error: ", err)
			return
		}

		if n != len(d) {
			fmt.Println("write error: ", err)
			return
		}
	}
	fmt.Println(w.String())
}

/* 自定义writer */
type MyWriter struct {
	ch chan byte
}

func NewMyWriter() (*MyWriter, error) {
	return &MyWriter{
		ch: make(chan byte),
	}, nil
}

func (w *MyWriter) Write(b []byte) (int, error) {
	n := 0
	for i := range b {
		w.ch <- b[i] // 复杂一点就要做原子操作
		n++
	}
	return n, nil
}

func (w *MyWriter) Close() error {
	close(w.ch)
	return nil
}

func MyWriterDemo() {
	data := []string{
		"hello world",
		"this is sean",
		"hahahaha",
	}
	w, _ := NewMyWriter()
	go func() {
		defer w.Close()
		for i := range data {
			w.Write([]byte(data[i]))
		}
	}()

	for d := range w.ch {
		fmt.Printf("%c", d)
	}
	fmt.Println()
}

/* Pipe 的 reader 与 writer */
func PipeDemo() {
	buf := new(bytes.Buffer)
	buf.WriteString("hello world")
	buf.WriteString("hello sean")
	buf.WriteString("hello this is hahhahah")

	pipeReader, pipeWriter := io.Pipe()
	go func() {
		defer pipeWriter.Close()
		io.Copy(pipeWriter, buf)
	}()

	io.Copy(os.Stdout, pipeReader)
	pipeReader.Close()
}

/* 缓冲IO */
func BufferIODemo() {
	file, err := os.Open("./planets.txt")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer file.Close()
	reader := bufio.NewReader(file) // 依据Reader建立带缓冲的Reader

	for {
		line, err := reader.ReadString('\n') // 读取一直到换行符
		if err != nil {
			if err == io.EOF {
				break
			} else {
				fmt.Println(err)
				os.Exit(1)
			}
		}
		fmt.Print(line)
	}
}

/* 标准包相关writer */
/*
// os.File
os.Create("./proverbs.txt")
file.Write([]byte(p))

// os.Stdout Stdin
os.Stdout.Write([]byte(p))

// io.Copy(io.Writer , io.Reader)  // 从reader中读取到writer中
if _, err := io.Copy(file, proverbs);

// io.WriterString()  // string 写入到 writer 中
if _, err := io.WriteString(file, "Go is fun!")
*/

/* ioutil包 */
func ioutilDemo() {
	bytes, err := os.ReadFile("./ts.txt")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Printf("%s", bytes)
}
